package main

import (
	"GinTest_api/global"
	"GinTest_api/initialize"
	"GinTest_api/untils"
	"GinTest_api/untils/register/consul"
	"fmt"
	"github.com/hashicorp/consul/api"
	uuid "github.com/satori/go.uuid"
	"go.uber.org/zap"
)

// 使用方式不同
// HTTP 接口只关注服务提供方，对于客户端怎么调用并不关心。接口只要保证有客户端调用时，返回对应的数据就行了。而RPC则要求客户端接口保持和服务端的一致
// 面向对象不同
// RPC，所谓的远程过程调用 ，是面向方法的 ，REST：所谓的 Representational state transfer ，是面向资源的
// 序列化协议不同
// json、xml、hession、protobuf、thrift、text、bytes -》rpc  -》 JSON-RPC，或者 XML-RPC
// JSON或者XML  http

//rpc可以基于tcp直接开发自己的协议，这个是可以保持长连接的，tcp的传输效率高，并且可以一直维持链接
//自定义协议可以优化数据的传输

//常见的分布式锁
//基于mysql的
//悲观锁  秒杀-减库存-超卖  需要关闭mysql的自动提交功能
//乐观锁  版本更新
//基于redis的分布式锁
//互斥性：任意时刻只能有一个客户端拥有锁，不能同时多个客户端获取
//安全性：锁只能被持有该锁的用户删除，而不能被其他用户删除
//基于zookeeper的分布式锁

// Raft算法  consul
// 基于Paxos算法的Raft变种算法  etcd
type ServerConfig struct {
	ServiceName   string      `mapstructure:"name"`
	ServerID      string      `mapstructure:"serverId"`
	ServerAddress string      `mapstructure:"serverAddress"`
	Tags          []string    `mapstructure:"tags"`
	Port          int         `mapstructure:"port"`
	MysqlInfo     MysqlConfig `mapstructure:"mysql"`
}

type MysqlConfig struct {
	Host string `mapstructure:"host"`

	Port int `mapstructure:"port"`
}

func NewLogger() (*zap.Logger, error) {
	cfg := zap.NewProductionConfig()
	cfg.OutputPaths = []string{ //可以定位到多个文件中
		"./myproject.log",
		"stderr",
		"stdout",
	}
	return cfg.Build()
}

// 注册服务
func registerToConsul(Name string, serviceID string, Port int, Tags []string, Address string) string {
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("%s:%d", global.ServerConfig.ConsulInfo.Host,
		global.ServerConfig.ConsulInfo.Port)

	client, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}
	//生成注册对象
	registration := new(api.AgentServiceRegistration)
	registration.Name = Name
	registration.ID = serviceID
	registration.Port = Port
	registration.Tags = Tags
	registration.Address = Address
	//registration.Check = check
	//1. 如何启动两个服务
	//2. 即使我能够通过终端启动两个服务，但是注册到consul中的时候也会被覆盖
	err = client.Agent().ServiceRegister(registration)
	if err != nil {
		panic(err)
	}
	return "请求成功"
}

// 获取所有服务
func AllServices() string {
	config := api.DefaultConfig()
	client, err := api.NewClient(config)
	if err != nil {
		panic(err)
	}
	data, err := client.Agent().Services()
	if err != nil {
		panic(err)
	}
	result := make([]interface{}, 0)

	for key, _ := range data {
		result = append(result, key)
	}
	return "请求成功"
}

// 过滤服务 (要哪个给哪个)
func FillterService() string {
	config := api.DefaultConfig()
	client, err := api.NewClient(config)
	if err != nil {
		panic(err)
	}
	data, err := client.Agent().ServicesWithFilter(`Service == "GinTest_api"`)
	if err != nil {
		panic(err)
	}
	result := make([]interface{}, 0)
	for key, _ := range data {
		result = append(result, key)
	}
	return "请求成功"

}

func main() {
	//1.初始化logger
	initialize.InitLogger()
	//将定义的全局变量赋值 2. 初始化配置   由最开始的读取所有配置改为只读取nacos配置
	initialize.InitConfig()
	//3. 初始化routers
	Router := initialize.Routers()
	//4. 初始化翻译
	if err := initialize.InitTrans("zh"); err != nil {
		panic(err)
	}
	//5. 初始化srv的连接
	initialize.InitSrvConfigs()
	//动态生成端口
	port, err := untils.GetAddr()
	if err == nil {
		global.ServerConfig.Port = port
	}
	global.ServerConfig.Port = port
	//serviceID := fmt.Sprintf("%s", uuid.NewV4())
	//registerToConsul("GinTest_Api", serviceID, port, []string{"GinTestApi", "Api"}, "10.3.159.10")

	//服务注册
	register_client := consul.NewRegistryClient(global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port)
	serviceId := fmt.Sprintf("%s", uuid.NewV4())
	err = register_client.Register(global.ServerConfig.Host, global.ServerConfig.Port, global.ServerConfig.Name, global.ServerConfig.Tags, serviceId)
	if err != nil {
		zap.S().Panic("服务注册失败:", err.Error())
	}
	zap.S().Debugf("启动服务器, 端口： %d", global.ServerConfig.Port)
	if err := Router.Run(fmt.Sprintf(":%d", global.ServerConfig.Port)); err != nil {
		zap.S().Panic("启动失败:", err.Error())
	}
}
